/////Process table implementation
#ifdef USER_PROGRAM

#include "process.h"

ProcessTable::ProcessTable()
{
	proccessTableLock = new Lock("Process Table Lock");
	numberOfActiveProcesses = 0;
	for (int i = 0; i < numberOfActiveProcesses; i++)
		numberOfThreads[i]=0;
	idCounter=0;
}

void ProcessTable::Add_Process_Entry(AddrSpace* incoming)
{
	proccessTableLock->Acquire();
	//Come up with unique SpaceId
	SpaceId newId = idCounter;
	//Associate unique id with this process
	processEntries[numberOfActiveProcesses].Associate_Id(newId);
	//Associate the incoming address space with this process
	processEntries[numberOfActiveProcesses].Associate_AddressSpace(incoming);
	//Increment number of active processes
	numberOfActiveProcesses++;
	idCounter++;
	proccessTableLock->Release();
}

void ProcessTable::Add_Thread_Entry(Thread* incoming, AddrSpace* space, int virtualAddrForTopOfStack)
{
	proccessTableLock->Acquire();
	//Associate thread with correct process
	int index;
	for (index = 0; index <numberOfActiveProcesses; index++)
	{
		if(space == processEntries[index].Get_AddressSpace())
			break;
	}
	if(index < numberOfActiveProcesses)
	{
		//Associate thread
		threadEntries[index][numberOfThreads[index]].Associate_Thread(incoming);
		//Set stack location
		threadEntries[index][numberOfThreads[index]].Associate_Stack_Location(virtualAddrForTopOfStack);
		if(processEntries[index].Get_Top_Of_Stack() < virtualAddrForTopOfStack)
			processEntries[index].Set_Top_Of_Stack(virtualAddrForTopOfStack);
		//Increment number of threads
		numberOfThreads[index]++;
	}
	proccessTableLock->Release();
	//else
		//Problem here.  Didn't find process in table with same address space

}

AddrSpace* ProcessTable::Get_AddressSpace(int id)
{
	proccessTableLock->Acquire();
	if (numberOfActiveProcesses>0)
	{
		proccessTableLock->Release();
		return processEntries[id].Get_AddressSpace();
	}
	else
	{
		proccessTableLock->Release();
		return NULL;
	}
}

int ProcessTable::Get_Num_Threads()
{
	proccessTableLock->Acquire();
	int sum=0;
	for(int i = 0; i<NUMBER_OF_PROCESSES; i++)
		 sum+=numberOfThreads[i];
	proccessTableLock->Release();
	return sum;
}

int ProcessTable::Get_Process_Id(AddrSpace* space)
{
	proccessTableLock->Acquire();
	int index;
	for (index = 0; index < numberOfActiveProcesses; index++)
	{
		if(space == processEntries[index].Get_AddressSpace())
			break;
	}
	if(index < numberOfActiveProcesses)
	{
		proccessTableLock->Release();
		return processEntries[index].Get_SpaceId();
	}
	if (numberOfActiveProcesses == 0)
	{
		proccessTableLock->Release();
		return 0;
	}
	proccessTableLock->Release();
	return -1;

}

bool ProcessTable::Is_Last_Thread_In_Process(AddrSpace* space)
{
	proccessTableLock->Acquire();
	int index;
	for (index = 0; index < numberOfActiveProcesses; index++)
	{
		if(space == processEntries[index].Get_AddressSpace())
			break;
	}
	if(index < numberOfActiveProcesses)
	{
		proccessTableLock->Release();
		return numberOfThreads[index]==0;
	}
	proccessTableLock->Release();
}

int ProcessTable::Get_Top_Of_Stack(Thread* incoming)
{
	proccessTableLock->Acquire();
	int index,indexTwo;
	for (index = 0; index < numberOfActiveProcesses; index++)
	{
		if(incoming->space == processEntries[index].Get_AddressSpace())
			break;
	}
	if(index < numberOfActiveProcesses)
	{
		for(indexTwo = 0; indexTwo < numberOfThreads[index]; indexTwo++)
		{
			if (incoming == threadEntries[index][indexTwo].Get_Thread())
				break;
		}
		if(indexTwo<numberOfThreads[index])
		{
			proccessTableLock->Release();
			return threadEntries[index][indexTwo].Get_Virtual_Stack_Location();
		}

	}
	proccessTableLock->Release();
	return -1;
}

void ProcessTable::Remove_Thread_Entry(Thread* incoming)
{
	proccessTableLock->Acquire();
	int index,indexTwo;
	for (index = 0; index < numberOfActiveProcesses; index++)
	{
		if(incoming->space == processEntries[index].Get_AddressSpace())
			break;
	}
	if(index < numberOfActiveProcesses)
	{
		for(indexTwo = 0; indexTwo < numberOfThreads[index]; indexTwo++)
		{
			if (incoming == threadEntries[index][indexTwo].Get_Thread())
				break;
		}
		if(indexTwo<numberOfThreads[index])
		{	
			//Copy over entry in array with next entry, fix the next entry, fix the next entry, etc
			for (int i = indexTwo; (indexTwo < numberOfThreads[index]) && (indexTwo < NUMBER_OF_THREADS_PER_PROCESS); indexTwo++)
			{
				threadEntries[index][indexTwo]=threadEntries[index][indexTwo+1];
			}
			numberOfThreads[index]--;
		}
		else
		{
			//printf("thread not found in process table\n");
		}
		//processEntries[index].Set_Top_Of_Stack(processEntries[index].Get_Top_Of_Stack()-8);
	}
	proccessTableLock->Release();
}

void ProcessTable::Remove_Process_Entry(AddrSpace* space)
{
	proccessTableLock->Acquire();
	int index;
	for (index = 0; index < numberOfActiveProcesses; index++)
	{
		if(space == processEntries[index].Get_AddressSpace())
			break;
	}
	if(index < numberOfActiveProcesses)
	{
		//threadEntries[index][0]=threadEntries[index][1];
		for (; (index < numberOfActiveProcesses) && (index < NUMBER_OF_PROCESSES); index++)
		{
			processEntries[index]=processEntries[index+1];
			for(int indexTwo = 0; indexTwo < numberOfThreads[index+1]; indexTwo++)
			{
				threadEntries[index][indexTwo]=threadEntries[index+1][indexTwo];
				numberOfThreads[index]=numberOfThreads[index+1];
			}
		}	
		
		numberOfActiveProcesses--;
	}
	else
	{
		//printf("Couldn't find process\n");
	}
	proccessTableLock->Release();
}

int ProcessTable::Get_Top_Of_Process_Stack(AddrSpace* space)
{
	proccessTableLock->Acquire();
	int index;
	for (index = 0; index < numberOfActiveProcesses; index++)
	{
		if(space == processEntries[index].Get_AddressSpace())
			break;
	}
	if(index < numberOfActiveProcesses)
	{
		proccessTableLock->Release();
		return processEntries[index].Get_Top_Of_Stack();
	}
	else
	{
		proccessTableLock->Release();
		return -1;
	}
}

ProcessTable::~ProcessTable()
{
	delete proccessTableLock;
}

ProcessEntry::ProcessEntry()
{
	topOfProcessStack=0;
	parentAddressSpace=NULL;
	id=-1;
}

void ProcessEntry::CleanUp()
{
	parentAddressSpace=NULL;
	id=-1;
}

ProcessEntry::~ProcessEntry()
{

}

ThreadEntry::ThreadEntry()
{
	thread = NULL;
}

ThreadEntry::~ThreadEntry()
{

}
#endif
